#pragma once
#include <iostream>
#include <sys/epoll.h>
#include "Log.hpp"
#include "Comm.hpp"
const static int gsize = 128;
class Mutiplex
{
public:
    Mutiplex() {};
    virtual ~Mutiplex() {};
    virtual bool AddEvent(int fd, uint32_t event) = 0;
    virtual bool DelEvent(int fd) = 0;
    virtual bool ModEvent(int fd, uint32_t event) = 0;
    virtual int Wait(struct epoll_event recvs[], int gnum, int timeout) = 0;
};

class Epoller
{
private:
    bool ModEventHelper(int fd, uint32_t event, int oper)
    {
        struct epoll_event ev;
        ev.data.fd = fd;
        ev.events = event;
        int n = ::epoll_ctl(_epfd, oper, fd, &ev);
        if (n < 0)
        {
            LOG(ERROR, "epoll_ctl %d and event %s error!\n", fd, EventToString(event).c_str());
            return false;
        }
        LOG(ERROR, "epoll_ctl %d and event %s success!\n", fd, EventToString(event).c_str());
        return true;
    }

public:
    Epoller()
    {
        _epfd = ::epoll_create(gsize);
        if (_epfd < 0)
        {
            LOG(FATAL, "epoll_create err,_epfd=%d\n", _epfd);
            exit(EPOLL_CREATE_ERROR);
        }
        else
        {
            LOG(INFO, "epoll_create success,_epfd=%d\n", _epfd);
        }
    }
    ~Epoller()
    {
        if (_epfd >= 0)
        {
            ::close(_epfd);
        }
    }

    const std::string EventToString(uint32_t event)
    {
        std::string str;
        if (event & EPOLLIN)
            str += "EPOLLIN|";
        if (event & EPOLLOUT)
            str += "EPOLLOUT|";
        if (event & EPOLLHUP)
            str += "EPOLLHUP|";
        if (event & EPOLLET)
            str += "|EPOLLET";
        return str;
    }

    int Wait(struct epoll_event recvs[], int gnum, int timeout)
    {
        return epoll_wait(_epfd, recvs, gnum, timeout);
    }

    bool AddEvent(int fd, uint32_t event)
    {
        return ModEventHelper(fd, event, EPOLL_CTL_ADD);
    }

    bool DelEvent(int fd)
    {
        return ::epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, nullptr);
    }

    bool ModEvent(int fd, uint32_t event)
    {
        return ModEventHelper(fd, event, EPOLL_CTL_MOD);
    }

private:
    int _epfd;
};
